home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 September / Macworld (1998-09).dmg / Shareware World / Info / For Developers / MacZoop 1.8.3 / Required Classes / Z Sources / ZEventHandler.cpp < prev    next >
Text File  |  1998-07-09  |  21KB  |  812 lines

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            MacZoop - "the framework for the rest of us"             
  5. *
  6. *
  7. *
  8. *            ZEventHandler.cpp        -- the event handler object
  9. *
  10. *
  11. *
  12. *
  13. *
  14. *            © 1996, Graham Cox
  15. *
  16. *
  17. *
  18. *
  19. *************************************************************************************************/
  20.  
  21. #include    "ZEventHandler.h"
  22. #include    "MacZoop.h"
  23. #include    "ProjectSettings.h"
  24. #include    "ZWindow.h"
  25. #include    "ZCommander.h"
  26. #include    "ZDialog.h"
  27.  
  28. #include    <LowMem.h>
  29. #include    <MixedMode.h>
  30.  
  31. // gSleep is the sleep period passed to WaitNextEvent
  32.  
  33. short            gSleep = kFrontSleep;
  34.  
  35. // gCurHandler is the current ZCommander object that wants to handle commands. This will
  36. // usually be the active window or the application
  37.  
  38. ZCommander*        gCurHandler = NULL;
  39.  
  40. // prototype of handler function for apple-events- sends them up the command chain.
  41.  
  42. static pascal OSErr        ZAEHandler ( AppleEvent* aeEvt, AppleEvent* reply, long refCon );
  43.  
  44. // global UPP to same
  45.  
  46. AEEventHandlerUPP        gAEUPP  = NewAEEventHandlerProc( ZAEHandler );
  47.  
  48.  
  49. /*-------------------------------***  CONSTRUCTOR  ***---------------------------------*/
  50.  
  51. ZEventHandler::ZEventHandler()
  52. {
  53.     clicks = 0;
  54.     inBackground = FALSE;
  55.     epPPCYokeDown = 0;
  56.     
  57.     gCurHandler = gApplication;
  58. }
  59.  
  60.  
  61. /*--------------------------***  ESTABLISHCURRENTHANDLER  ***---------------------------*/
  62. /*    
  63.  
  64. set up the value of <gCurHandler> by querying the active window
  65. ----------------------------------------------------------------------------------------*/
  66.  
  67. void    ZEventHandler::EstablishCurrentHandler()
  68. {
  69.     ZWindow*    zw = gWindowManager->GetTopWindow();
  70.     
  71.     // we only dispatch Idle if the window is active.
  72.     
  73.     if ( zw && zw->IsActive())
  74.         gCurHandler = zw->GetHandler();    // this method returns the handler within the window
  75.                                         // or the window itself.
  76.     else
  77.         gCurHandler = gApplication;
  78. }
  79.  
  80.  
  81. /*---------------------------------***  GETANEVENT  ***---------------------------------*/
  82. /*    
  83.  
  84. gets the next event off the queue. If it's a null event, give idle time
  85.  
  86. ----------------------------------------------------------------------------------------*/
  87.  
  88. void    ZEventHandler::GetAnEvent( EventRecord* theEvent, const short mask )
  89. {
  90.     // gets an event from the event queue and sets "theEvent" to it. On the PowerPC, WNE is
  91.     // an emulated trap and performance can be enhanced by calling it much less frequently
  92.     // than once per loop. If we're running on PowerPC, we use the "epPPCYokeDown" variable
  93.     // to count our main loops. If we do not call WNE, we pretend that the event is a NULL
  94.     // event. The default is 32 loops per event.
  95.     
  96. #if GENERATINGPOWERPC
  97.  
  98.     Boolean        isIdle;
  99.     
  100.     // for some events, we want to immediately handle them. However, calling EventAvail
  101.     // offsets some of the advantage of doing this yokedown anyway, so we check this
  102.     // every four calls to try and keep the speed improvement as good as possible. As always
  103.     // this is a tradeoff between good responsiveness and fast execution.
  104.     
  105.     if (( epPPCYokeDown % 4 ) == 0 )
  106.     {
  107.         if ( EventAvail( mDownMask + keyDownMask + updateMask, theEvent ))
  108.             epPPCYokeDown = 0;
  109.     }
  110.     
  111.     if ( epPPCYokeDown <= 0 )
  112.     {
  113.         isIdle = ! WaitNextEvent( mask, theEvent, gSleep, NULL );
  114.         epPPCYokeDown = kPowerPCWNEYokeDown;
  115.     }
  116.     else
  117.     {
  118.         theEvent->what = nullEvent;
  119.         theEvent->message = 0;
  120.         theEvent->when = TickCount();
  121.         
  122.         GetMouse( &theEvent->where );
  123.         LocalToGlobal( &theEvent->where );
  124.         
  125.         theEvent->modifiers = GetModifiers();
  126.         
  127.         // decrement loop counter
  128.         
  129.         isIdle = TRUE;
  130.         epPPCYokeDown--;
  131.     }
  132.     
  133.     if ( isIdle )
  134.         PassIdle();
  135.  
  136. #else
  137.  
  138.     if (! WaitNextEvent( mask, theEvent, gSleep, NULL ))
  139.         PassIdle();
  140.  
  141. #endif
  142.  
  143.     // if we have "dynamic menu bar hiding" enabled, make that happen:
  144.     
  145.     #if _AUTO_MBAR_HIDING
  146.     
  147.     if ( ! inBackground )
  148.         gMenuBar->ShowHideMenuBar( MBAR_HIDE_MOUSEAWARE, theEvent->where );
  149.     
  150.     #endif
  151.         
  152.     // dispatch the cursor to the current window, so it's shape can be set.
  153.     
  154.     if ( !inBackground )
  155.     {
  156.         ZWindow*    aZW = gWindowManager->LocateWindow( theEvent->where );
  157.         
  158.         if ( aZW )
  159.         {
  160.             WindowPtr w = aZW->GetMacWindow();
  161.         
  162.             // check to see that the window is not "windowshaded"- if
  163.             // it is, don't dispatch the cursor. If the window is shaded,
  164.             // its contRgn will be empty.
  165.             
  166.             if (! EmptyRgn( ((WindowPeek) w)->contRgn ))
  167.             {
  168.                 if ( aZW )
  169.                 {
  170.                     Point        mouse;
  171.                     GrafPtr        savePort;
  172.                     
  173.                     mouse = theEvent->where;
  174.                     
  175.                     GetPort( &savePort );
  176.                     SetPort( w );
  177.                     GlobalToLocal( &mouse );
  178.                     SetPort( savePort );
  179.  
  180.                     // if the point is inside the window, dispatch to the window,
  181.                     // otherwise reset the cursor to an arrow. If the window is not the top
  182.                     // window, the cursor is not dispatched, but reset, unless the window is
  183.                     // a floater, in which case we do dispatch it if there not a modal dialog
  184.                     // in front of it. The result is correct for what the user expects.
  185.                     
  186.                     if     ( PtInRect( mouse, &w->portRect ) &&
  187.                         ( aZW == gApplication->GetFrontWindow() ||
  188.                         ( aZW->Floats() && ! gWindowManager->IsDialog( gApplication->GetFrontWindow()))))
  189.                         aZW->AdjustCursor( mouse, theEvent->modifiers );
  190.                     else
  191.                         gApplication->MouseNotInAnyWindow( theEvent->where );
  192.                 }
  193.             }
  194.             else
  195.                 gApplication->MouseNotInAnyWindow( theEvent->where );
  196.         }
  197.         else
  198.             gApplication->MouseNotInAnyWindow( theEvent->where );
  199.     }
  200. }
  201.  
  202.  
  203. /*-----------------------------***  DISPATCHANEVENT  ***--------------------------------*/
  204. /*    
  205.  
  206. determine what sort of event it is and call the relevant handler method.
  207.  
  208. ----------------------------------------------------------------------------------------*/
  209.  
  210. void    ZEventHandler::DispatchAnEvent( EventRecord* theEvent )
  211. {
  212.     // dispatches the event according to its type, etc
  213.     
  214.     Boolean        isAutoKey = FALSE;
  215.     char         theKey;
  216.     
  217.     FailNILParam( theEvent );
  218.     lastEvent = *theEvent;
  219.             
  220.     // set up gCurHandler
  221.     
  222.     EstablishCurrentHandler();
  223.  
  224.     // see if this is a dialog event and process it. Note that for floaters to work, we can't use
  225.     // IsDialogEvent, since it assumes FrontWindow() returns the active document- with floaters, 
  226.     // this is not true, so we have to ask our own wMgr object to check for us.
  227.  
  228.     if ( gWindowManager->CheckDialogEvent( theEvent ))
  229.     {
  230.         // allow the event to be modified before the dialog processes it.
  231.         
  232.         if ( PrefilterDialogEvent( theEvent ))
  233.             return;    // event was fully handled
  234.     }
  235.     
  236.     // dispatch the event to the handler
  237.     
  238.     switch ( theEvent->what )
  239.     {
  240.         case mouseDown:
  241.             HandleMouseEvent( *theEvent );
  242.             break;
  243.         
  244.         case activateEvt:
  245.             
  246.             // following defined in Project Settings.h
  247.             
  248.             #if _ACTIVATE_EVENTS_ARE_REAL
  249.             HandleWindowActivate(    (WindowPtr) theEvent->message,
  250.                                     (theEvent->modifiers & activeFlag) );
  251.             #endif
  252.             break;
  253.         
  254.         case autoKey:
  255.             isAutoKey = TRUE;
  256.         
  257.         case keyDown:
  258.             theKey = theEvent->message & charCodeMask;
  259.             
  260.             HandleKeyEvent( theKey, isAutoKey, theEvent->modifiers );
  261.             break;
  262.         
  263.         case updateEvt:
  264.             HandleWindowUpdate((WindowPtr) theEvent->message );
  265.             break;
  266.         
  267.         case diskEvt:
  268.         {
  269.             Point dPt = {100,100};
  270.             
  271.             if( HiWord( theEvent->message ) != 0)
  272.                 DIBadMount( dPt, theEvent->message );
  273.             break;
  274.         }
  275.         
  276.         case kHighLevelEvent:
  277.             HandleHLEvent( *theEvent );
  278.             break;
  279.         
  280.         case osEvt:
  281.             HandleOSEvent( *theEvent );
  282.             break;
  283.     }
  284. }
  285.  
  286.  
  287. /*------------------------------***  HANDLEKEYEVENT  ***--------------------------------*/
  288. /*    
  289.  
  290. process keystrokes. Command-Key sequences are passed to the menu handler
  291. ----------------------------------------------------------------------------------------*/
  292.  
  293. void    ZEventHandler::HandleKeyEvent( const char theKey, const Boolean isAutoKey, short modifiers )
  294. {
  295.     long mSelect;
  296.     
  297.     if ( modifiers & cmdKey )
  298.     {
  299.         // if this is a command-key combination, translate this to a
  300.         // menu command as if it were picked from the menu.
  301.         
  302.         if (! isAutoKey)
  303.         {
  304.             gMenuBar->DimMenus();
  305.             
  306.             // ask the command chain to reenable the relevant menu items
  307.             
  308.             if ( gCurHandler )
  309.                 gCurHandler->UpdateMenus();
  310.             
  311.             mSelect = MenuKey( theKey );
  312.             
  313.             gMenuBar->DispatchCommand( mSelect );
  314.         }    
  315.     }
  316.     else
  317.     {
  318.         // the user is typing- send the characters to the current commander
  319.         
  320.         if ( gCurHandler )
  321.             gCurHandler->Type( theKey, modifiers );
  322.     }
  323. }
  324.  
  325.  
  326. /*-------------------------***  PREFILTERDIALOGEVENT  ***-------------------------------*/
  327. /*    
  328.  
  329. opportunity to prefilter the event for a dialog before the dialog manager gets it. This
  330. determines which dialog object to call, and calls its filter function. This is how
  331. return and enter keys, etc, are processed.
  332.  
  333. ----------------------------------------------------------------------------------------*/
  334.  
  335. Boolean    ZEventHandler::PrefilterDialogEvent( EventRecord* theEvent )
  336. {
  337.     Boolean        handled = FALSE;
  338.     
  339.     ZDialog*    zDW = dynamic_cast<ZDialog*> ( gApplication->GetFrontWindow());
  340.     
  341.     if ( zDW )
  342.         handled = zDW->Filter( theEvent );
  343.  
  344.     return handled;
  345. }
  346.  
  347.  
  348. /*-------------------------------***  COUNTCLICKS  ***----------------------------------*/
  349. /*    
  350.  
  351. count up the number of rapid mouse-clicks to detect double-clicks, etc.
  352.  
  353. ----------------------------------------------------------------------------------------*/
  354.  
  355. void    ZEventHandler::CountClicks( const WindowPtr target, const long clickTicks, const Point globalMouse )
  356. {
  357.     static    WindowPtr     prevTarget = NULL;
  358.     static    long        lastClickTicks = 0;
  359.     static    Point        lastClick = {0,0};
  360.     
  361.     GrafPtr    savePort;
  362.     Point    gMouse;
  363.     
  364.     gMouse = globalMouse;
  365.     
  366.     GetPort( &savePort );
  367.     SetPort( target );
  368.     GlobalToLocal( &gMouse );
  369.     
  370.     if (target == prevTarget)
  371.     {
  372.         // the target window is the same as the last click, is the click
  373.         // within the double-click period set by the user?
  374.         
  375.         if ( clickTicks < lastClickTicks + GetDblTime())
  376.         {
  377.             // yes, the click is in time. Finally, we ask the window
  378.             // whether we should consider the click as being in the same place.    
  379.             
  380.             ZWindow*    zW = GetZWindow( target );
  381.             
  382.             if ( zW && zW->ClickInSamePlace( lastClick, gMouse ))
  383.                 clicks++;
  384.             else
  385.                 clicks = 1;
  386.         }
  387.         else
  388.             clicks = 1;
  389.     }
  390.     else
  391.         clicks = 1;
  392.     
  393.     // store the click point, target and click time for the next time
  394.             
  395.     lastClick = gMouse;
  396.     prevTarget = target;
  397.     lastClickTicks = clickTicks;
  398.  
  399.     SetPort( savePort );
  400. }
  401.  
  402.  
  403. /*---------------------------***  HANDLEMOUSEEVENT  ***---------------------------------*/
  404. /*    
  405.  
  406. handle mouse button clicks. This finds the target window or other part of the screen
  407.  
  408. ----------------------------------------------------------------------------------------*/
  409.  
  410. void    ZEventHandler::HandleMouseEvent( const EventRecord& theEvent)
  411. {
  412.     WindowPtr        targetWindow;
  413.     short            partCode;
  414.     long            mSelect;
  415.     Point            mousePt;
  416.     ZWindow*        zappWindow;
  417.     
  418.     // find out what part of the screen the mouse was clicked on
  419.     
  420.     partCode = FindWindow( theEvent.where, &targetWindow );
  421.     
  422.     // if it was any sort of window, get the ZWindow object associated with it, if any.
  423.     
  424.     if ( targetWindow )
  425.         zappWindow = GetZWindow( targetWindow );
  426.     
  427.     switch (partCode)
  428.     {    
  429.         case inDesk:
  430.             SysBeep( 1 );
  431.             break;
  432.         
  433.         case inMenuBar:
  434.             // the user clicked the menubar.
  435.  
  436.             gMenuBar->ClickMenuBar( theEvent.where );
  437.             
  438.             break;
  439.         
  440.         case inSysWindow:
  441.             SystemClick( &theEvent, targetWindow );    // system will handle it (DA window)
  442.             break;
  443.         
  444.         case inContent:
  445.             if ( targetWindow )                        // the user clicked in a window
  446.             {
  447.                 // if there's a modal dialog up, clicks in other windows result in a beep.
  448.                 
  449.                 ZWindow*    aZW = gApplication->GetFrontWindow();
  450.                 ZDialog*    aZD;
  451.                 
  452.                 if ( aZW )
  453.                     aZD = dynamic_cast<ZDialog*> ( aZW );
  454.                 else
  455.                     aZD = NULL;
  456.                     
  457.                 Boolean        dialogUp = ( aZD && aZD->IsModal());
  458.                 
  459.                 CountClicks( targetWindow, theEvent.when, theEvent.where );    // double click?
  460.                 
  461.                 // if the window is top window or top floater, pass the click to the window.
  462.                 
  463.                 if( zappWindow &&
  464.                     (zappWindow == gApplication->GetFrontWindow() ||
  465.                     (zappWindow == gWindowManager->GetTopFloater() && ! dialogUp )))
  466.                 {
  467.                     // if the window is already active, pass the click to the window object
  468.                     // in its local coordinate system.
  469.                     
  470.                     mousePt = theEvent.where;
  471.                     
  472.                     zappWindow->Focus();
  473.                     GlobalToLocal( &mousePt );
  474.                     zappWindow->Click( mousePt, theEvent.modifiers );    
  475.                 }
  476.                 else
  477.                 {
  478.                     // if the window wasn't active, make it active. If there is a modal dialog in
  479.                     // front, then this action is not permitted.
  480.                     
  481.                     if ( dialogUp )
  482.                     {
  483.                         SysBeep( 1 );
  484.                         break;
  485.                     }
  486.                     // otherwise, process the click    
  487.  
  488.                     if ( zappWindow )
  489.                     {
  490.                         // make this window the active one
  491.                         
  492.                         zappWindow->Select();
  493.                         
  494.                         // if the window is a floater, ask it to process the click as well- 
  495.                         // floaters process "front" clicks even when they were not initially
  496.                         // active, since floaters are all 'peers' of one another.
  497.                     
  498.                         if ( zappWindow->Floats())
  499.                         {
  500.                             mousePt = theEvent.where;
  501.                             
  502.                             zappWindow->Focus();
  503.                             GlobalToLocal( &mousePt );
  504.                             zappWindow->Click( mousePt, theEvent.modifiers );
  505.                         }
  506.                     }
  507.                 }
  508.             }
  509.             break;
  510.         
  511.         case inDrag:
  512.         {
  513.             // the user wants to drag the window. Only permit this if no
  514.             // modal dialog is in front of it, or the command key is down.
  515.             
  516.             ZDialog*    aZD = (ZDialog*) gApplication->GetFrontWindow();
  517.             
  518.             if ((((WindowPeek) aZD->GetMacWindow())->windowKind == dialogKind) &&
  519.                 aZD->IsModal() &&
  520.                 (targetWindow != aZD->GetMacWindow()) &&
  521.                 ! (theEvent.modifiers & cmdKey))
  522.             {
  523.                 SysBeep( 1 );
  524.                 break;
  525.             }
  526.             ZWindow*    zw = GetZWindow( targetWindow );
  527.             gWindowManager->DragWindowOutline( zw, theEvent.where, theEvent.modifiers );
  528.             
  529.             break;
  530.         }
  531.         
  532.         case inGrow:
  533.         {
  534.             // the user wants to resize the window
  535.             
  536.             Rect szRect;
  537.             
  538.             if ( zappWindow )
  539.             {
  540.                 zappWindow->GetSizeRect( &szRect );
  541.                 
  542.                 szRect.right++;
  543.                 szRect.bottom++;
  544.                 
  545.                 mSelect = GrowWindow( targetWindow, theEvent.where, &szRect );
  546.             
  547.                 if ( mSelect )
  548.                 {
  549.                     // if the command key was down, then we are attempting to override the
  550.                     // current settings for sizerect. Thus we need to change the size rect
  551.                     // to the desired size first:
  552.                     
  553.                     if ( theEvent.modifiers & cmdKey )
  554.                     {
  555.                         szRect.right = MAX( LoWord( mSelect ), szRect.right - 1 );
  556.                         szRect.bottom = MAX( HiWord( mSelect ), szRect.bottom - 1 );
  557.                         
  558.                         zappWindow->SetSizeRect( szRect );
  559.                     }
  560.                     
  561.                     zappWindow->SetSize( LoWord( mSelect ), HiWord( mSelect ));
  562.                 }
  563.             }
  564.             break;
  565.         }
  566.         
  567.         case inGoAway:
  568.             if ( TrackGoAway( targetWindow, theEvent.where ))
  569.             {
  570.                 // if the user clicks in the go-away box, the window will be closed. If the
  571.                 // option key is down, we close all of the windows.
  572.                 
  573.                 if ( theEvent.modifiers & optionKey )
  574.                     gApplication->CloseAll( zappWindow->Floats());
  575.                 else
  576.                 {
  577.                     if ( zappWindow )
  578.                         zappWindow->Close( gApplication->GetPhase());
  579.                 }
  580.             }
  581.             break;
  582.         
  583.         case inZoomIn:
  584.         case inZoomOut:
  585.             if( TrackBox( targetWindow, theEvent.where, partCode ))
  586.             {
  587.                 // if the user clicked in the zoom box, the window will be zoomed
  588.                 
  589.                 if( zappWindow )
  590.                     zappWindow->Zoom( partCode );
  591.             }
  592.             break;
  593.     }
  594. }
  595.  
  596.  
  597. /*---------------------------***  HANDLEWINDOWUPDATE  ***-------------------------------*/
  598. /*    
  599.  
  600. to handle an update event, call the window object's update method.
  601.  
  602. ----------------------------------------------------------------------------------------*/
  603.  
  604. void    ZEventHandler::HandleWindowUpdate( const WindowPtr theWindow )
  605. {
  606.     ZWindow*        zappWindow = NULL;
  607.     Boolean            memState;
  608.     
  609.     if ( theWindow )
  610.         zappWindow = GetZWindow( theWindow );
  611.     
  612.     memState = gApplication->MemoryCrisis();
  613.     
  614.     if ( zappWindow )
  615.         zappWindow->PerformUpdate();
  616.         
  617.     // if the draw resulted in a memory shortage, suppress the warning, since
  618.     // that will trigger further updates, etc.
  619.         
  620.     if ( gApplication->MemoryCrisis() != memState )
  621.         gApplication->userHasSeenAlert = TRUE;
  622. }
  623.  
  624.  
  625.  
  626. /*---------------------------------***  PASSIDLE  ***-----------------------------------*/
  627. /*    
  628.  
  629. send the idle command to the current handler, and pass it up the chain
  630.  
  631. ----------------------------------------------------------------------------------------*/
  632.  
  633.  
  634. void    ZEventHandler::PassIdle()
  635. {
  636.     // called repeatedly for null events. This passes idle messages to the current commander
  637.     
  638.     EstablishCurrentHandler();
  639.  
  640.     if ( gCurHandler )
  641.         gCurHandler->Idle();
  642.         
  643.     // floaters may want idle time too, though they are not part of the command chain. We
  644.     // ask the window manager to give them time:
  645.     
  646.     gWindowManager->FloatIdle();
  647. }
  648.  
  649.  
  650.  
  651. /*--------------------------***  HANDLEWINDOWACTIVATE  ***------------------------------*/
  652. /*    
  653.  
  654. calls activate/deactivate for window
  655. ----------------------------------------------------------------------------------------*/
  656.  
  657. void    ZEventHandler::HandleWindowActivate( const WindowPtr theWindow, const Boolean state )
  658. {
  659.     // handles the activate and deactivate events. This calls the window object with
  660.     // the activate messages, and also sets up gCurHandler.
  661.  
  662.     ZWindow*        zw = NULL;
  663.     
  664.     if ( theWindow )
  665.         zw = GetZWindow( theWindow );
  666.     
  667.     if ( zw )
  668.     {
  669.         zw->Focus();
  670.         if ( state )
  671.             zw->Activate();
  672.         else
  673.             zw->Deactivate();
  674.     }
  675. }
  676.  
  677.  
  678. /*------------------------------***  HANDLEOSEVENT  ***---------------------------------*/
  679. /*    
  680.  
  681. handle the suspend and resume events sent by MultiFinder/System 7
  682. ----------------------------------------------------------------------------------------*/
  683.  
  684. void    ZEventHandler::HandleOSEvent( const EventRecord& theEvent )
  685. {
  686.     if ((( theEvent.message & 0xFF000000 ) >> 24 ) == suspendResumeMessage )
  687.     {
  688.         if ( theEvent.message & resumeFlag )
  689.         {
  690.             inBackground = FALSE;
  691.             gSleep = kFrontSleep;
  692.             gWindowManager->Resume();
  693.             
  694.             if ( theEvent.message & convertClipboardFlag )    
  695.                 gClipboard->ConvertToPrivate();
  696.                 
  697.             ResumeCursorAnimation();
  698.         }
  699.         else
  700.         {
  701.             inBackground = TRUE;
  702.             gSleep = kBackSleep;
  703.             gMenuBar->ShowHideMenuBar( MBAR_SHOW );
  704.             gClipboard->ConvertFromPrivate();
  705.             gWindowManager->Suspend();
  706.             PauseCursorAnimation( 0 );
  707.         }
  708.         
  709.         SetCursorShape( ARROW_CURSOR );    
  710.     }
  711. }
  712.  
  713.  
  714. /*------------------------------***  HANDLEHLEVENT  ***---------------------------------*/
  715. /*    
  716.  
  717. handle the high level events sent by AOCE, Applescript, et al.
  718. ----------------------------------------------------------------------------------------*/
  719.  
  720. void    ZEventHandler::HandleHLEvent( const EventRecord& theEvent)
  721. {
  722.     // handles high level events such as applescript events, etc.
  723.     
  724.     FailOSErr( AEProcessAppleEvent( &theEvent ));
  725. }
  726.  
  727.  
  728. /*-----------------------***  INSTALLAPPLESCRIPTHANDLERS  ***---------------------------*/
  729. /*    
  730.  
  731. install the handler vectors needed to field applescript events. BY default this installs
  732. the four required events. You can override this to install more, or call the method
  733. below as needed.
  734. ----------------------------------------------------------------------------------------*/
  735.  
  736. void    ZEventHandler::InstallApplescriptHandlers()
  737. {
  738.     InstallAppleEventHandler( kCoreEventClass, kAEOpenApplication );
  739.     InstallAppleEventHandler( kCoreEventClass, kAEOpenDocuments );
  740.     InstallAppleEventHandler( kCoreEventClass, kAEPrintDocuments );
  741.     InstallAppleEventHandler( kCoreEventClass, kAEQuitApplication );
  742.     
  743.     // MacOS 8 has a new core apple event for reopening the application...
  744.     
  745.     if ( gMacInfo.systemVersion >= 0x0800 )
  746.         InstallAppleEventHandler( kCoreEventClass, kAEReopenApplication );
  747. }
  748.  
  749.  
  750. /*------------------------***  INSTALLAPPLEEVENTHANDLER  ***----------------------------*/
  751. /*    
  752.  
  753. install the handler vector needed to field all applescript events. Call this once for
  754. each event class and ID you wish to process. Apple Events will be unpacked by the global
  755. vector proc and sent up the command chain. You can intercept them there and process them
  756. as needed.
  757. ----------------------------------------------------------------------------------------*/
  758.  
  759. void    ZEventHandler::InstallAppleEventHandler( const AEEventClass pClass, const AEEventID pID )
  760. {
  761.     // installs the AppleEvent hook for the given apple event
  762.     
  763.     if ( gMacInfo.hasAppleEvents )
  764.         FailOSErr( AEInstallEventHandler( pClass, pID, gAEUPP, (long) gApplication, FALSE ));
  765. }
  766.  
  767.  
  768. #pragma mark -
  769. /*---------------------------------*********************---------------------------------*/
  770.  
  771.  
  772. static pascal OSErr            ZAEHandler( AppleEvent* aeEvt, AppleEvent* reply, long refCon )
  773. {
  774.     // this is the global vector proc that is called for every apple event. This determines the
  775.     // event class and ID, then sends that info, plus the event, up the command chain, where,
  776.     // presumably, it will be handled.
  777.  
  778.     AEEventClass    pClass;
  779.     AEEventID        pID;
  780.     DescType        returnedType;
  781.     long            returnedSize;
  782.     OSErr            theErr = noErr;
  783.     
  784.     try
  785.     {
  786.         // determine the AE class and ID (this is laborious, so it's done here once and passed on)
  787.     
  788.         FailOSErr( AEGetAttributePtr(     aeEvt, keyEventClassAttr,
  789.                                          typeType, &returnedType,
  790.                                          &pClass, sizeof( AEEventClass ), &returnedSize ));
  791.  
  792.         FailOSErr( AEGetAttributePtr(     aeEvt, keyEventIDAttr,
  793.                                          typeType, &returnedType,
  794.                                          &pID, sizeof( AEEventID ), &returnedSize ));
  795.  
  796.         if ( gCurHandler )
  797.         {
  798.             gCurHandler->HandleAppleEvent( pClass, pID, aeEvt, reply );
  799.             theErr = noErr;
  800.         }
  801.         else
  802.             theErr = errAEEventNotHandled;
  803.     }
  804.     catch( OSErr err )
  805.     {
  806.         theErr = err;
  807.     }
  808.     
  809.     return theErr;
  810. }            
  811.  
  812.